package gee

import (
	"log"
	"net/http"
	"strings"
)

type HandlerFunc func(ctx *Context)

type router struct {
	handlers map[string]HandlerFunc
	engine   *Engine
}

func newRouter() *router {
	return &router{

		handlers: make(map[string]HandlerFunc)}
}

func parsePattern(pattern string) []string {

	vs := strings.Split(pattern, "/")

	parts := make([]string, 0, len(vs))
	for _, v := range vs {
		if v != "" {
			parts = append(parts, v)
			if v[0] == '*' {
				break
			}
		}
	}

	return parts
}

func (r *router) addRoute(method, pattern string, handlerFunc HandlerFunc) {
	log.Printf("Route %4s - %s", method, pattern)
	key := method + "-" + pattern

	root := r.engine.trees.get(method)
	if root == nil {
		root = &node{}
		tree := methodTree{
			method: method,
			root:   root,
		}
		r.engine.trees = append(r.engine.trees, tree)
	}

	root.insert(pattern, parsePattern(pattern), 0)
	r.handlers[key] = handlerFunc
}

func (r *router) getRoute(method, path string) (*node, map[string]string) {

	root := r.engine.trees.get(method)
	if root == nil {
		return nil, nil
	}

	searchParts := parsePattern(path)
	n := root.search(searchParts, 0)
	if n == nil {
		return nil, nil
	}

	params := make(map[string]string)
	for index, part := range parsePattern(n.pattern) {
		if part[0] == ':' {
			params[part[1:]] = searchParts[index]
		}
		if part[0] == '*' && len(part) > 1 {
			params[part[1:]] = strings.Join(searchParts[index:], "/")
			break
		}
	}

	return n, params
}

func (r *router) handle(c *Context) {
	route, m := r.getRoute(c.Method, c.Path)
	if route == nil {
		c.handlers = append(c.handlers, func(c *Context) {
			c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
		})
	} else {
		c.Params = m
		key := c.Method + "-" + route.pattern

		c.handlers = append(c.handlers, r.handlers[key])
	}

	c.Next()
}
